home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP07.ZIP / CHAP07 / PATRON / PAGES.CPP < prev    next >
C/C++ Source or Header  |  1993-06-07  |  27KB  |  1,206 lines

  1. /*
  2.  * PAGES.CPP
  3.  * Modifications for Chapter 7
  4.  *
  5.  * Implementation of the CPages class.  See PAGEWIN.CPP for additional
  6.  * member functions.
  7.  *
  8.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Software Design Engineer
  11.  * Microsoft Systems Developer Relations
  12.  *
  13.  * Internet  :  kraigb@microsoft.com
  14.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  15.  */
  16.  
  17.  
  18.  
  19. #include "patron.h"
  20.  
  21.  
  22. HWND        g_hDlgPrint=NULL;
  23. BOOL        g_fCancelPrint=FALSE;
  24.  
  25.  
  26. /*
  27.  * CPages:CPages
  28.  * CPages::~CPages
  29.  *
  30.  * Constructor Parameters:
  31.  *  hInst           HINSTANCE of the application we're in.
  32.  *  cf              UINT application clipboard format.
  33.  */
  34.  
  35. //CHAPTER7MOD
  36. CPages::CPages(HINSTANCE hInst, UINT cf)
  37.     : CWindow(hInst)
  38.     {
  39.     m_pPageCur=NULL;
  40. //End CHAPTER7MOD
  41.     m_iPageCur=0xFFFF;  //Pages are 0 indexed, so this is one before that.
  42.     m_cPages=0;
  43.     m_hWndPageList=NULL;
  44.  
  45.     /*
  46.      * Initialize to 2.54cm*2.54cm which is a page with no space for anything,
  47.      * just margins.  2.54cm=.5 inches on each margin.
  48.      */
  49.     m_cx=LOMETRIC_PER_INCH;
  50.     m_cy=LOMETRIC_PER_INCH;
  51.  
  52.     m_xPos=0L;
  53.     m_yPos=0L;
  54.  
  55.     m_dwIDNext=0;
  56.     m_pIStorage=NULL;
  57.  
  58.     //CHAPTER7MOD
  59.     m_fDirty=FALSE;
  60.     m_cf=cf;
  61.     //End CHAPTER7MOD
  62.     return;
  63.     }
  64.  
  65.  
  66. CPages::~CPages(void)
  67.     {
  68.     //Insure memory is cleaned up in list, and do final IStorage::Release
  69.     FIStorageSet(NULL, FALSE, FALSE);
  70.  
  71.     if (NULL!=m_hFont && !m_fSystemFont)
  72.         DeleteObject(m_hFont);
  73.  
  74.     if (NULL!=m_hWndPageList)
  75.         DestroyWindow(m_hWndPageList);
  76.  
  77.     //m_hWnd destroyed with the document.
  78.     return;
  79.     }
  80.  
  81.  
  82.  
  83. //CHAPTER7MOD
  84. /*
  85.  * CPages::FIsDirty
  86.  *
  87.  * Purpose:
  88.  *  Tells the caller (document) if anything's happened to dirty us.
  89.  *
  90.  * Parameters:
  91.  *  None
  92.  *
  93.  * Return Value:
  94.  *  None
  95.  */
  96.  
  97. BOOL CPages::FIsDirty(void)
  98.     {
  99.     return m_fDirty;
  100.     }
  101. //End CHAPTER7MOD
  102.  
  103.  
  104.  
  105. /*
  106.  * CPages::FInit
  107.  *
  108.  * Purpose:
  109.  *  Instantiates a pages window within a given parent.  The
  110.  *  parent may be a main application window, could be an MDI child
  111.  *  window. We really do not care.
  112.  *
  113.  * Parameters:
  114.  *  hWndParent      HWND of the parent of this window
  115.  *  pRect           LPRECT that this window should occupy
  116.  *  dwStyle         DWORD containing the window's style flags.  Should
  117.  *                  contain WS_CHILD | WS_VISIBLE in typical circumstances.
  118.  *  uID             UINT ID to associate with this window
  119.  *  pv              LPVOID unused for now.
  120.  *
  121.  * Return Value:
  122.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  123.  */
  124.  
  125. BOOL CPages::FInit(HWND hWndParent, LPRECT pRect, DWORD dwStyle
  126.     , UINT uID, LPVOID pv)
  127.     {
  128.     int     cy;
  129.  
  130.     m_hWnd=CreateWindowEx(WS_EX_NOPARENTNOTIFY, SZCLASSPAGES
  131.         , SZCLASSPAGES, dwStyle, pRect->left, pRect->top
  132.         , pRect->right-pRect->left, pRect->bottom-pRect->top
  133.         , hWndParent, (HMENU)uID, m_hInst, (LPVOID)this);
  134.  
  135.     if (NULL==m_hWnd)
  136.         return FALSE;
  137.  
  138.     /*
  139.      * Create the hidden listbox we'll use to track pages.  We give it
  140.      * the owner-draw style so we can just store pointers in it.  We have
  141.      * to set the parent to NULL such that the window hangs around after
  142.      * the pages window is destroyed so that we can clean up the
  143.      * memory stored in it from the CPages destructor.
  144.      */
  145.     m_hWndPageList=CreateWindow("listbox", "Page List", WS_POPUP | LBS_OWNERDRAWFIXED
  146.         , 0, 0, 100, 100, HWND_DESKTOP, NULL, m_hInst, NULL);
  147.  
  148.     if (NULL==m_hWndPageList)
  149.         return FALSE;
  150.  
  151.     //Create a 14 point Arial font, or use the system variable font.
  152.     cy=MulDiv(-14, LOMETRIC_PER_INCH, 72);
  153.     m_hFont=CreateFont(cy, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE
  154.         , ANSI_CHARSET, OUT_TT_PRECIS, CLIP_TT_ALWAYS, PROOF_QUALITY
  155.         , VARIABLE_PITCH | FF_SWISS, "Arial");
  156.  
  157.     if (NULL==m_hFont)
  158.         {
  159.         m_hFont=(HFONT)GetStockObject(ANSI_VAR_FONT);
  160.         m_fSystemFont=TRUE;
  161.         }
  162.  
  163.     return TRUE;
  164.     }
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171. /*
  172.  * CPages::FIStorageSet
  173.  *
  174.  * Purpose:
  175.  *  Provides the document's IStorage to the pages for its own uses.
  176.  *  If this is a new storage, then we initalize it with streams we
  177.  *  want to always exists.  If this is an open, then we create
  178.  *  our page list from the PageList string we wrote before.
  179.  *
  180.  * Parameters:
  181.  *  pIStorage       LPSTORAGE to the new or opened storage.  If this is
  182.  *                  NULL then we just clean up and exit.
  183.  *  fChange         BOOL indicating is this was a Save As operation
  184.  *                  meaning that we have the structure already, we
  185.  *                  just need to change our value of m_pIStorage.
  186.  *  fInitNew        BOOL indicating if this is a new storage or one
  187.  *                  opened from a previous save.
  188.  *
  189.  * Return Value:
  190.  *  None
  191.  */
  192.  
  193. BOOL CPages::FIStorageSet(LPSTORAGE pIStorage, BOOL fChange, BOOL fInitNew)
  194.     {
  195.     DWORD           dwMode=STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  196.     HRESULT         hr;
  197.     LPPAGE          pPage;
  198.     BOOL            fRet=FALSE;
  199.     ULONG           cbRead;
  200.     PAGELIST        pgList;
  201.     LPSTREAM        pIStream;
  202.     LPMALLOC        pIMalloc;
  203.     LPDWORD         pdwID;
  204.     UINT            i;
  205.  
  206.     //If we're just changing saved roots, just open the current page again
  207.     if (fChange)
  208.         {
  209.         if (NULL==pIStorage)
  210.             return FALSE;
  211.  
  212.         m_pIStorage->Release();
  213.         m_pIStorage=pIStorage;
  214.         m_pIStorage->AddRef();
  215.  
  216.         //CHAPTER7MOD
  217.         FPageGet(m_iPageCur, &m_pPageCur, TRUE);
  218.         //End CHAPTER7MOD
  219.         return TRUE;
  220.         }
  221.  
  222.     if (NULL!=m_hWndPageList)
  223.         {
  224.         //On new or open, clean out whatever it is we have.
  225.         for (i=0; i < m_cPages; i++)
  226.             {
  227.             if (FPageGet(i, &pPage, FALSE))
  228.                 delete pPage;
  229.             }
  230.  
  231.         SendMessage(m_hWndPageList, LB_RESETCONTENT, 0, 0L);
  232.         }
  233.  
  234.     if (NULL!=m_pIStorage)
  235.         m_pIStorage->Release();
  236.  
  237.     m_pIStorage=NULL;
  238.  
  239.     //If we're just cleaning up, then we're done.
  240.     if (NULL==pIStorage)
  241.         return TRUE;
  242.  
  243.     m_pIStorage=pIStorage;
  244.     m_pIStorage->AddRef();
  245.  
  246.     //If this is a new storage, create the streams we require
  247.     if (fInitNew)
  248.         {
  249.         //Page list header.
  250.         hr=m_pIStorage->CreateStream(SZSTREAMPAGELIST, dwMode | STGM_CREATE
  251.             , 0, 0, &pIStream);
  252.  
  253.         if (FAILED(hr))
  254.             return FALSE;
  255.  
  256.         pIStream->Release();
  257.  
  258.         //Device Configuration
  259.         hr=m_pIStorage->CreateStream(SZSTREAMDEVICECONFIG, dwMode | STGM_CREATE
  260.             , 0, 0, &pIStream);
  261.  
  262.         if (FAILED(hr))
  263.             return FALSE;
  264.  
  265.         pIStream->Release();
  266.         return TRUE;
  267.         }
  268.  
  269.  
  270.     /*
  271.      * We're opening an existing file:
  272.      *  1)  Configure for the device we're on
  273.      *  2)  Read the Page List and create page entries for each.
  274.      */
  275.  
  276.     ConfigureForDevice();
  277.  
  278.     //Read the page list.
  279.     hr=m_pIStorage->OpenStream(SZSTREAMPAGELIST, NULL, dwMode, 0, &pIStream);
  280.  
  281.     if (FAILED(hr))
  282.         return FALSE;
  283.  
  284.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  285.         {
  286.         pIStream->Read((LPVOID)&pgList, sizeof(PAGELIST), &cbRead);
  287.         m_cPages  =(UINT)pgList.cPages;
  288.         m_iPageCur=(UINT)pgList.iPageCur;
  289.         m_dwIDNext=pgList.dwIDNext;
  290.  
  291.         fRet=TRUE;
  292.         cbRead=pgList.cPages*sizeof(DWORD);
  293.  
  294.         if (0!=cbRead)
  295.             {
  296.             pdwID=(LPDWORD)pIMalloc->Alloc(cbRead);
  297.  
  298.             if (NULL!=pdwID)
  299.                 {
  300.                 pIStream->Read((LPVOID)pdwID, cbRead, &cbRead);
  301.  
  302.                 for (i=0; i < m_cPages; i++)
  303.                     fRet &=FPageAdd(-1, *(pdwID+i), FALSE); //-1==end of list
  304.  
  305.                 pIMalloc->Free((LPVOID)pdwID);
  306.                 }
  307.             }
  308.  
  309.         pIMalloc->Release();
  310.         }
  311.  
  312.     pIStream->Release();
  313.  
  314.     if (!fRet)
  315.         return FALSE;
  316.  
  317.     //CHPATER7MOD
  318.     FPageGet(m_iPageCur, &m_pPageCur, TRUE);
  319.     //End CHAPTER7MOD
  320.  
  321.     InvalidateRect(m_hWnd, NULL, FALSE);
  322.     UpdateWindow(m_hWnd);
  323.  
  324.     return TRUE;
  325.     }
  326.  
  327.  
  328.  
  329.  
  330.  
  331. /*
  332.  * CPages::FIStorageUpdate
  333.  *
  334.  * Purpose:
  335.  *  Insures that all pages are committed before a root save.
  336.  *
  337.  * Parameters:
  338.  *  fCloseAll       BOOL directing us to close all open storages and streams.
  339.  *
  340.  * Return Value:
  341.  *  BOOL            TRUE if successful, FALSE otherwise.
  342.  */
  343.  
  344. BOOL CPages::FIStorageUpdate(BOOL fCloseAll)
  345.     {
  346.     LPPAGE          pPage;
  347.     LPSTREAM        pIStream;
  348.     LPMALLOC        pIMalloc;
  349.     LPDWORD         pdwID;
  350.     ULONG           cb;
  351.     HRESULT         hr;
  352.     PAGELIST        pgList;
  353.     BOOL            fRet=FALSE;
  354.     UINT            i;
  355.  
  356.     //We only need to possibly close the current page--nothing else is open.
  357.     //CHAPTER7MOD
  358.     if (NULL!=m_pPageCur)
  359.         {
  360.         m_pPageCur->Update();
  361.  
  362.         if (fCloseAll)
  363.             m_pPageCur->Close(FALSE);
  364.         }
  365.     //End CHAPTER7MOD
  366.  
  367.     //We don't hold anything else open, so we can just write the page list.
  368.     hr=m_pIStorage->OpenStream(SZSTREAMPAGELIST, NULL, STGM_DIRECT
  369.         | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  370.  
  371.     if (FAILED(hr))
  372.         return FALSE;
  373.  
  374.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  375.         {
  376.         pgList.cPages=m_cPages;
  377.         pgList.iPageCur=m_iPageCur;
  378.         pgList.dwIDNext=m_dwIDNext;
  379.  
  380.         pIStream->Write((LPVOID)&pgList, sizeof(PAGELIST), &cb);
  381.  
  382.         cb=m_cPages*sizeof(DWORD);
  383.         pdwID=(LPDWORD)pIMalloc->Alloc(cb);
  384.  
  385.         if (NULL!=pdwID)
  386.             {
  387.             for (i=0; i < m_cPages; i++)
  388.                 {
  389.                 FPageGet(i, &pPage, FALSE);
  390.                 *(pdwID+i)=pPage->GetID();
  391.                 }
  392.  
  393.             pIStream->Write((LPVOID)pdwID, cb, &cb);
  394.             pIMalloc->Free((LPVOID)pdwID);
  395.             fRet=TRUE;
  396.             }
  397.         pIMalloc->Release();
  398.         }
  399.  
  400.     pIStream->Release();
  401.  
  402.     //CHAPTER7MOD
  403.     //Don't forget to clean up the dirty flag when we do an update.
  404.     m_fDirty=!fRet;
  405.     //End CHAPTER7MOD
  406.     return fRet;
  407.     }
  408.  
  409.  
  410.  
  411.  
  412.  
  413.  
  414.  
  415. /*
  416.  * CPages::RectGet
  417.  *
  418.  * Purpose:
  419.  *  Returns the rectangle of the Pages window in parent coordinates.
  420.  *
  421.  * Parameters:
  422.  *  pRect           LPRECT in which to return the rectangle.
  423.  *
  424.  * Return Value:
  425.  *  None
  426.  */
  427.  
  428. void CPages::RectGet(LPRECT pRect)
  429.     {
  430.     RECT        rc;
  431.     POINT       pt;
  432.  
  433.     //Retrieve the size of our rectangle in parent coordinates.
  434.     GetWindowRect(m_hWnd, &rc);
  435.     SETPOINT(pt, rc.left, rc.top);
  436.     ScreenToClient(GetParent(m_hWnd), &pt);
  437.  
  438.     SetRect(pRect, pt.x, pt.y, pt.x+(rc.right-rc.left)
  439.         , pt.y+(rc.bottom-rc.top));
  440.  
  441.     return;
  442.     }
  443.  
  444.  
  445.  
  446.  
  447.  
  448.  
  449. /*
  450.  * CPages::RectSet
  451.  *
  452.  * Purpose:
  453.  *  Sets a new rectangle for the Pages window which sizes to fit.
  454.  *  Coordinates are given in parent terms.
  455.  *
  456.  * Parameters:
  457.  *  pRect           LPRECT containing the new rectangle.
  458.  *  fNotify         BOOL indicating if we're to notify anyone of the change.
  459.  *
  460.  * Return Value:
  461.  *  None
  462.  */
  463.  
  464. void CPages::RectSet(LPRECT pRect, BOOL fNotify)
  465.     {
  466.     UINT        cx, cy;
  467.  
  468.     if (NULL==pRect)
  469.         return;
  470.  
  471.     cx=pRect->right-pRect->left;
  472.     cy=pRect->bottom-pRect->top;
  473.  
  474.     SetWindowPos(m_hWnd, NULL, pRect->left, pRect->top
  475.         , (UINT)cx, (UINT)cy, SWP_NOZORDER);
  476.  
  477.     UpdateScrollRanges();
  478.     return;
  479.     }
  480.  
  481.  
  482.  
  483.  
  484. /*
  485.  * CPages::SizeGet
  486.  *
  487.  * Purpose:
  488.  *  Retrieves the size of the pages window in parent coordinates.
  489.  *
  490.  * Parameters:
  491.  *  pRect           LPRECT in which to return the size.  The right and
  492.  *                  bottom fields will contain the dimensions.
  493.  *
  494.  * Return Value:
  495.  *  None
  496.  */
  497.  
  498. void CPages::SizeGet(LPRECT pRect)
  499.     {
  500.     RectGet(pRect);
  501.     return;
  502.     }
  503.  
  504.  
  505.  
  506.  
  507.  
  508.  
  509.  
  510. /*
  511.  * CPages::SizeSet
  512.  *
  513.  * Purpose:
  514.  *  Sets a new size in parent coordinates for the Pages window.
  515.  *
  516.  * Parameters:
  517.  *  pRect           LPRECT containing the new rectangle.
  518.  *  fNotify         BOOL indicating if we're to notify anyone of the change.
  519.  *
  520.  * Return Value:
  521.  *  None
  522.  */
  523.  
  524. void CPages::SizeSet(LPRECT pRect, BOOL fNotify)
  525.     {
  526.     UINT        cx, cy;
  527.  
  528.     if (NULL==pRect)
  529.         return;
  530.  
  531.     cx=pRect->right-pRect->left;
  532.     cy=pRect->bottom-pRect->top;
  533.  
  534.     SetWindowPos(m_hWnd, NULL, 0, 0, (UINT)cx, (UINT)cy
  535.         , SWP_NOMOVE | SWP_NOZORDER);
  536.  
  537.     UpdateScrollRanges();
  538.     return;
  539.     }
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546. /*
  547.  * CPages::PageInsert
  548.  *
  549.  * Purpose:
  550.  *  Creates a new page immediately after the current page.  If there
  551.  *  are no pages then this creates page 1.
  552.  *
  553.  * Parameters:
  554.  *  uReserved       UINT unused
  555.  *
  556.  * Return Value:
  557.  *  UINT            Index of the new page, 0 on failure.
  558.  */
  559.  
  560. UINT CPages::PageInsert(UINT uReserved)
  561.     {
  562.     if (0!=m_cPages && NULL!=m_pPageCur)
  563.         {
  564.         //Close the current page, committing changes.
  565.         m_pPageCur->Close(TRUE);
  566.         }
  567.  
  568.     //Create and open the new page.
  569.     if (!FPageAdd(m_iPageCur, m_dwIDNext, TRUE))
  570.         return 0;
  571.  
  572.     m_dwIDNext++;
  573.     m_iPageCur++;
  574.     m_cPages++;
  575.  
  576.     InvalidateRect(m_hWnd, NULL, FALSE);
  577.     UpdateWindow(m_hWnd);
  578.  
  579.     FPageGet(m_iPageCur, &m_pPageCur, FALSE);
  580.     return m_iPageCur;
  581.     }
  582.  
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589. /*
  590.  * CPages::PageDelete
  591.  *
  592.  * Removes the current page from the page list.
  593.  *
  594.  * Parameters:
  595.  *  uReserved       UINT unused
  596.  *
  597.  * Return Value:
  598.  *  UINT            Index to the now current page from the page list,
  599.  *                  -1 on error.
  600.  */
  601.  
  602. UINT CPages::PageDelete(UINT uReserved)
  603.     {
  604.     //CHAPTER7MOD
  605.     //Delete the page in both the storage and in memory.
  606.     SendMessage(m_hWndPageList, LB_DELETESTRING, m_iPageCur, 0L);
  607.  
  608.     m_pPageCur->Destroy(m_pIStorage);
  609.  
  610.     delete m_pPageCur;   //Does final pPage->Close
  611.     m_pPageCur=NULL;
  612.     //End CHAPTER7MOD
  613.  
  614.     /*
  615.      * If this is the last page then the current is one less.  If it's
  616.      * the only page the current is zero.  Otherwise the current is the
  617.      * next page.
  618.      */
  619.  
  620.     if (m_iPageCur==m_cPages-1)   //Covers last or only page.
  621.         m_iPageCur--;
  622.  
  623.     m_cPages--;
  624.  
  625.     //Insure the new visible page is open.
  626.     if (0!=m_cPages)
  627.         {
  628.         FPageGet(m_iPageCur, &m_pPageCur, TRUE);
  629.         InvalidateRect(m_hWnd, NULL, FALSE);
  630.         }
  631.     else
  632.         InvalidateRect(m_hWnd, NULL, TRUE);
  633.  
  634.     UpdateWindow(m_hWnd);
  635.     return m_iPageCur;
  636.     }
  637.  
  638.  
  639.  
  640.  
  641.  
  642.  
  643. /*
  644.  * CPages::CurPageGet
  645.  *
  646.  * Purpose:
  647.  *  Retrieves the index of the current page we're viewing.
  648.  *
  649.  * Parameters:
  650.  *  None
  651.  *
  652.  * Return Value:
  653.  *  UINT            Index of the current page.
  654.  */
  655.  
  656. UINT CPages::CurPageGet(void)
  657.     {
  658.     return m_iPageCur;
  659.     }
  660.  
  661.  
  662.  
  663.  
  664.  
  665. /*
  666.  * CPages::CurPageSet
  667.  *
  668.  * Purpose:
  669.  *  Sets the index of the current page to view.
  670.  *
  671.  * Parameters:
  672.  *  iPage           UINT index of the page to view. 0 means first page,
  673.  *                  -1 means last page.
  674.  *
  675.  * Return Value:
  676.  *  UINT            Index of the previous current page, -1 on error.
  677.  */
  678.  
  679. UINT CPages::CurPageSet(UINT iPage)
  680.     {
  681.     UINT    iPagePrev=m_iPageCur;
  682.     LPPAGE  pPage;
  683.  
  684.     //Close the old page committing changes.
  685.     if (!FPageGet(iPagePrev, &pPage, FALSE))
  686.         return -1;
  687.  
  688.     pPage->Close(TRUE);
  689.  
  690.     switch (iPage)
  691.         {
  692.         case 0:
  693.             m_iPageCur=0;
  694.             break;
  695.  
  696.         case (UINT)-1:
  697.             m_iPageCur=m_cPages-1;
  698.             break;
  699.  
  700.         default:
  701.             if (iPage >= m_cPages)
  702.                 iPage=0;
  703.  
  704.             m_iPageCur=iPage;
  705.             break;
  706.         }
  707.  
  708.     //Open the new page.
  709.     FPageGet(m_iPageCur, &m_pPageCur, TRUE);
  710.  
  711.     InvalidateRect(m_hWnd, NULL, FALSE);
  712.     UpdateWindow(m_hWnd);
  713.     return iPagePrev;
  714.     }
  715.  
  716.  
  717.  
  718.  
  719.  
  720. /*
  721.  * CPages::NumPagesGet
  722.  *
  723.  * Purpose:
  724.  *  Returns the number of pages this object current contains.
  725.  *
  726.  * Parameters:
  727.  *  None
  728.  *
  729.  * Return Value:
  730.  *  UINT            Number of pages we contain.
  731.  */
  732.  
  733. UINT CPages::NumPagesGet(void)
  734.     {
  735.     return m_cPages;
  736.     }
  737.  
  738.  
  739.  
  740.  
  741.  
  742. /*
  743.  * CPages::DevModeSet
  744.  *
  745.  * Purpose:
  746.  *  Provides the Pages with the current printer information.
  747.  *
  748.  * Parameters:
  749.  *  hDevMode        HGLOBAL to the memory containing the DEVMODE.  This
  750.  *                  function assumes responsibility for this handle.
  751.  *  hDevNames       HGLOBAL providing the driver name and device name
  752.  *                  from which we can create a DC for information.
  753.  *
  754.  *
  755.  * Return Value:
  756.  *  BOOL            TRUE if we could accept this configuration, FALSE
  757.  *                  otherwise.  If we return TRUE we also delete the old
  758.  *                  memory we hold.
  759.  */
  760.  
  761. BOOL CPages::DevModeSet(HGLOBAL hDevMode, HGLOBAL hDevNames)
  762.     {
  763.     LPDEVNAMES      pdn;
  764.     LPSTR           psz;
  765.     DEVICECONFIG    dc;
  766.     LPDEVMODE       pdm;
  767.     LPSTREAM        pIStream;
  768.     HRESULT         hr;
  769.     ULONG           cbWrite;
  770.     BOOL            fRet=FALSE;
  771.  
  772.     if (NULL==hDevMode || NULL==hDevNames)
  773.         return FALSE;
  774.  
  775.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  776.         | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  777.  
  778.     if (FAILED(hr))
  779.         return FALSE;
  780.  
  781.     pdm=(LPDEVMODE)GlobalLock(hDevMode);
  782.  
  783.     if (NULL!=pdm)
  784.         {
  785.         dc.dm=*pdm;
  786.         GlobalUnlock(hDevMode);
  787.  
  788.         psz=(LPSTR)GlobalLock(hDevNames);
  789.  
  790.         if (NULL!=psz)
  791.             {
  792.             pdn=(LPDEVNAMES)psz;
  793.             lstrcpy(dc.szDriver, psz+pdn->wDriverOffset);
  794.             lstrcpy(dc.szDevice, psz+pdn->wDeviceOffset);
  795.             lstrcpy(dc.szPort,   psz+pdn->wOutputOffset);
  796.  
  797.             pIStream->Write((LPVOID)&dc, sizeof(DEVICECONFIG), &cbWrite);
  798.             GlobalUnlock(hDevNames);
  799.             fRet=TRUE;
  800.             }
  801.         }
  802.  
  803.     pIStream->Release();
  804.  
  805.     if (!fRet)
  806.         return FALSE;
  807.  
  808.     GlobalFree(hDevNames);
  809.     GlobalFree(hDevMode);
  810.     return ConfigureForDevice();
  811.     }
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818. /*
  819.  * CPages::DevModeGet
  820.  *
  821.  * Purpose:
  822.  *  Retrieves a copy of the current DEVMODE structure for this Pages window.
  823.  *  The caller is responsible for this memory.
  824.  *
  825.  * Parameters:
  826.  *  None
  827.  *
  828.  * Return Value:
  829.  *  HGLOBAL         Handle to the memory containing the DEVMODE structure.
  830.  */
  831.  
  832. HGLOBAL CPages::DevModeGet(void)
  833.     {
  834.     HGLOBAL     hMem;
  835.     LPDEVMODE   pdm;
  836.     ULONG       cbRead;
  837.     LPSTREAM    pIStream;
  838.     HRESULT     hr;
  839.  
  840.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  841.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  842.  
  843.     if (FAILED(hr))
  844.         return FALSE;
  845.  
  846.     hMem=GlobalAlloc(GHND, sizeof(DEVMODE));
  847.  
  848.     if (NULL!=hMem)
  849.         {
  850.         pdm=(LPDEVMODE)GlobalLock(hMem);
  851.         pIStream->Read((LPVOID)pdm, sizeof(DEVMODE), &cbRead);
  852.         GlobalUnlock(hMem);
  853.         }
  854.  
  855.     pIStream->Release();
  856.     return hMem;
  857.     }
  858.  
  859.  
  860.  
  861.  
  862. //CHAPTER7MOD
  863. /*
  864.  * CPages::DevReadConfig
  865.  *
  866.  * Purpose:
  867.  *  Public function to read the current device configuration and optionally
  868.  *  return an information context for it.
  869.  *
  870.  * Parameters:
  871.  *  pdc             LPDEVICECONFIG in which to store the configuration.
  872.  *                  This may be NULL in which case no information is
  873.  *                  returned.
  874.  *  phDC            HDC FAR * in which to return the information context.
  875.  *                  If NULL, no IC is created.  Caller becomes responsible
  876.  *                  for the returned IC.
  877.  *
  878.  * Return Value:
  879.  *  BOOL            TRUE if successful, FALSE otherwise.
  880.  */
  881.  
  882. BOOL CPages::DevReadConfig(LPDEVICECONFIG pdc, HDC FAR *phDC)
  883.     {
  884.     HRESULT         hr;
  885.     LPSTREAM        pIStream;
  886.     ULONG           cbRead;
  887.     DEVICECONFIG    dc;
  888.  
  889.     if (NULL==pdc)
  890.         pdc=&dc;
  891.  
  892.     //Read the DEVMODE and driver names from our header stream.
  893.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  894.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  895.  
  896.     if (FAILED(hr))
  897.         return FALSE;
  898.  
  899.     pIStream->Read((LPVOID)pdc, sizeof(DEVICECONFIG), &cbRead);
  900.     pIStream->Release();
  901.  
  902.     if (NULL!=phDC)
  903.         {
  904.         //Get the DC then configure
  905.         *phDC=CreateIC(pdc->szDriver, pdc->szDevice, pdc->szPort, &pdc->dm);
  906.  
  907.         if (NULL==*phDC)
  908.             return FALSE;
  909.         }
  910.  
  911.     return TRUE;
  912.     }
  913. //End CHAPTER7MOD
  914.  
  915.  
  916.  
  917.  
  918.  
  919. /*
  920.  * CPages::ConfigureForDevice
  921.  *
  922.  * Purpose:
  923.  *  Recalculates our drawing configuration based on the contents of
  924.  *  an hDC.  If no HDC is given we use the contents of our DevMode stream.
  925.  *
  926.  * Parameters:
  927.  *  None
  928.  *
  929.  * Return Value:
  930.  *  BOOL            TRUE if successful, FALSE otherwise.
  931.  */
  932.  
  933. BOOL CPages::ConfigureForDevice(void)
  934.     {
  935.     POINT           ptOffset, ptPaper;
  936.     RECT            rc;
  937.     HDC             hDC;
  938.  
  939.     //CHAPTER7MOD
  940.     if (!DevReadConfig(NULL, &hDC))
  941.         return FALSE;
  942.     //End CHAPTER7MOD
  943.  
  944.     //Get usable page dimensions:  already sensitive to orientation
  945.     m_cx=GetDeviceCaps(hDC, HORZSIZE)*10;   //*10 converts mm to LOMETRIC
  946.     m_cy=GetDeviceCaps(hDC, VERTSIZE)*10-8; //-8 accounts for driver bugs.
  947.  
  948.     //Calculate the printer-limited margins on each side in LOMETRIC.
  949.     Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, (LPVOID)&ptOffset);
  950.     Escape(hDC, GETPHYSPAGESIZE,   NULL, NULL, (LPVOID)&ptPaper);
  951.  
  952.     SetRect(&rc, ptOffset.x, ptOffset.y, ptPaper.x, ptPaper.y);
  953.     SetMapMode(hDC, MM_LOMETRIC);
  954.     RectConvertMappings(&rc, hDC, FALSE);
  955.  
  956.     //Left and top margins are the printing offset.
  957.     m_xMarginLeft= rc.left;
  958.     m_yMarginTop =-rc.top;  //LOMETRIC makes this negative.
  959.  
  960.     //Right is (paper width)-(usable width)-(left margin)
  961.     m_xMarginRight =rc.right-m_cx-m_xMarginLeft;
  962.  
  963.     //Bottom is (paper height)-(usable height)-(top margin).
  964.     m_yMarginBottom=-rc.bottom-m_cy-m_yMarginTop;
  965.  
  966.     UpdateScrollRanges();
  967.  
  968.     DeleteDC(hDC);
  969.     return TRUE;
  970.     }
  971.  
  972.  
  973.  
  974. //CHAPTER7MOD
  975. /*
  976.  * CPages::TenantCreate
  977.  * CPages::TenantDestroy
  978.  *
  979.  * Purpose:
  980.  *  Pass-throughs for CPage members on the current page.
  981.  */
  982.  
  983. BOOL CPages::TenantCreate(TENANTTYPE tType, LPVOID pv, LPFORMATETC pFE
  984.     , LPPATRONOBJECT ppo, DWORD dwData)
  985.     {
  986.     BOOL    fRet;
  987.  
  988.     if (NULL==m_pPageCur)
  989.         return FALSE;
  990.  
  991.     fRet=m_pPageCur->TenantCreate(tType, pv, pFE, ppo, dwData);
  992.     m_fDirty |= fRet;
  993.     return fRet;
  994.     }
  995.  
  996.  
  997. BOOL CPages::TenantDestroy(void)
  998.     {
  999.     BOOL    fRet;
  1000.  
  1001.     if (NULL==m_pPageCur)
  1002.         return FALSE;
  1003.  
  1004.     fRet=m_pPageCur->TenantDestroy();
  1005.     m_fDirty |= fRet;
  1006.     return fRet;
  1007.     }
  1008.  
  1009.  
  1010.  
  1011. /*
  1012.  * CPages::TenantClip
  1013.  *
  1014.  * Purpose:
  1015.  *  Copies or cuts the currently selected tenant to the clipoard.
  1016.  *
  1017.  * Parameters:
  1018.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  1019.  *
  1020.  * Return Value:
  1021.  *  BOOL            TRUE if successful, FALSE otherwise.
  1022.  */
  1023.  
  1024. BOOL CPages::TenantClip(BOOL fCut)
  1025.     {
  1026.     BOOL    fRet;
  1027.  
  1028.     if (NULL==m_pPageCur)
  1029.         return FALSE;
  1030.  
  1031.     fRet=m_pPageCur->TenantClip(fCut);
  1032.     m_fDirty |= (fRet && fCut);
  1033.     return fRet;
  1034.     }
  1035.  
  1036.  
  1037.  
  1038.  
  1039.  
  1040.  
  1041. /*
  1042.  * CPages::FQueryObjectSelected
  1043.  *
  1044.  * Purpose:
  1045.  *  Returns whether or not there is an object selected on this
  1046.  *  page for Cut, Copy, Delete functions.
  1047.  *
  1048.  * Parameters:
  1049.  *  hMenu           HMENU of the Edit menu.
  1050.  *
  1051.  * Return Value:
  1052.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  1053.  */
  1054.  
  1055. BOOL CPages::FQueryObjectSelected(HMENU hMenu)
  1056.     {
  1057.     if (NULL==m_pPageCur)
  1058.         return FALSE;
  1059.  
  1060.     return m_pPageCur->FQueryObjectSelected(hMenu);
  1061.     }
  1062.  
  1063.  
  1064.  
  1065.  
  1066. /*
  1067.  * CPages::CalcBoundingRect
  1068.  * (Protected)
  1069.  *
  1070.  * Purpose:
  1071.  *  Calculates a rectangle that bounds the printed page and the
  1072.  *  current scroll state of the window.
  1073.  *
  1074.  * Parameters:
  1075.  *  prc             LPRECT to fill with window (device) coordinates.
  1076.  *  fWindow         BOOL indicating to include the window in this
  1077.  *                  calculation or return only the printed page coordinates.
  1078.  *
  1079.  * Return Value:
  1080.  *  None
  1081.  */
  1082.  
  1083. void CPages::CalcBoundingRect(LPRECT prc, BOOL fWindow)
  1084.     {
  1085.     RECT        rc, rcT;
  1086.  
  1087.     if (NULL==prc)
  1088.         return;
  1089.  
  1090.     //Calculate the boundaries for sizing: intersect page & screen
  1091.     rc.left=LOMETRIC_BORDER+m_xMarginLeft;
  1092.     rc.top =-LOMETRIC_BORDER-m_yMarginTop;
  1093.     rc.right =rc.left+(UINT)m_cx;
  1094.     rc.bottom=rc.top -(UINT)m_cy;
  1095.     RectConvertMappings(&rc, NULL, TRUE);
  1096.     OffsetRect(&rc, -(int)m_xPos, -(int)m_yPos);
  1097.  
  1098.     if (!fWindow)
  1099.         {
  1100.         *prc=rc;
  1101.         return;
  1102.         }
  1103.  
  1104.     //Intersect with window to make the size bounds.
  1105.     GetClientRect(m_hWnd, &rcT);
  1106.     IntersectRect(prc, &rc, &rcT);
  1107.     return;
  1108.     }
  1109.  
  1110. //End CHAPTER7MOD
  1111.  
  1112.  
  1113.  
  1114.  
  1115.  
  1116. /*
  1117.  * CPages::FPageGet
  1118.  * (Protected)
  1119.  *
  1120.  * Purpose:
  1121.  *  Returns a page of a given index returning a BOOL so it's simple
  1122.  *  to use this function inside if statements.
  1123.  *
  1124.  * Parameters:
  1125.  *  iPage           UINT page to retrieve 0 based.
  1126.  *  ppPage          LPPAGE FAR * in which to return the page pointer
  1127.  *  fOpen           BOOL indicating if we should open this page as well.
  1128.  *
  1129.  * Return Value:
  1130.  *  BOOL            TRUE if successful, FALSE otherwise.
  1131.  */
  1132.  
  1133. BOOL CPages::FPageGet(UINT iPage, LPPAGE FAR *ppPage, BOOL fOpen)
  1134.     {
  1135.     if (NULL==ppPage)
  1136.         return FALSE;
  1137.  
  1138.     if (sizeof(LPPAGE)==SendMessage(m_hWndPageList, LB_GETTEXT, iPage
  1139.         , (LONG)(LPVOID)ppPage))
  1140.         {
  1141.         if (fOpen)
  1142.             (*ppPage)->FOpen(m_pIStorage);
  1143.  
  1144.         return TRUE;
  1145.         }
  1146.  
  1147.     return FALSE;
  1148.     }
  1149.  
  1150.  
  1151.  
  1152.  
  1153.  
  1154.  
  1155. /*
  1156.  * CPages::FPageAdd
  1157.  * (Protected)
  1158.  *
  1159.  * Purpose:
  1160.  *  Creates a new page initialized to the given values.  The new page's
  1161.  *  storage is created if it does not already exist.  If fOpenStorage
  1162.  *  is set the the page's storage is opened and left opened.
  1163.  *
  1164.  * Parameters:
  1165.  *  iPage           UINT Location at which to insert page; new page is
  1166.  *                  inserted after this position.  0xFFFF for the end.
  1167.  *  dwID            DWORD ID for this page.
  1168.  *  fOpenStorage    BOOL indicating if we're to leave the storage open.
  1169.  *
  1170.  * Return Value:
  1171.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  1172.  */
  1173.  
  1174. BOOL CPages::FPageAdd(UINT iPage, DWORD dwID, BOOL fOpenStorage)
  1175.     {
  1176.     LPPAGE      pPage;
  1177.     LRESULT     lr;
  1178.  
  1179.     //CHAPTER7MOD
  1180.     pPage=new CPage(dwID, m_hWnd, this);
  1181.     //End CHAPTER7MOD
  1182.  
  1183.     if (NULL==pPage)
  1184.         return FALSE;
  1185.  
  1186.     if (fOpenStorage)
  1187.         pPage->FOpen(m_pIStorage);
  1188.  
  1189.     if (0xffff==iPage)
  1190.         iPage--;
  1191.  
  1192.     //Now try to add to the listbox.
  1193.     lr=SendMessage(m_hWndPageList, LB_INSERTSTRING, iPage+1, (LONG)pPage);
  1194.  
  1195.     if (LB_ERRSPACE==lr)
  1196.         {
  1197.         if (fOpenStorage)
  1198.             pPage->Close(FALSE);
  1199.  
  1200.         delete pPage;
  1201.         return FALSE;
  1202.         }
  1203.  
  1204.     return TRUE;
  1205.     }
  1206.